package cn.com.common.qrcode;

import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Shape;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URL;
import java.util.Date;
import java.util.Hashtable;

import javax.imageio.ImageIO;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.Result;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

public class QRCodeUtil {
	private static final String CHARSET = "utf-8";

	public static BufferedImage createImage(String content, String imgPath,
			int QRCodeSize) {
		try {
			Hashtable hashtable = new Hashtable();
			hashtable.put(EncodeHintType.ERROR_CORRECTION,
					ErrorCorrectionLevel.H);
			hashtable.put(EncodeHintType.CHARACTER_SET, CHARSET);
			hashtable.put(EncodeHintType.MARGIN, 1);
			BitMatrix bitMatrix = new MultiFormatWriter().encode(content,
					BarcodeFormat.QR_CODE, QRCodeSize, QRCodeSize, hashtable);
			int width = bitMatrix.getWidth();
			int height = bitMatrix.getHeight();
			BufferedImage image = new BufferedImage(width, height,
					BufferedImage.TYPE_INT_RGB);
			for (int x = 0; x < width; x++) {
				for (int y = 0; y < height; y++) {
					image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000
							: 0xFFFFFFFF);
				}
			}
			if (imgPath == null || "".equals(imgPath)) {
				return image;
			}
			QRCodeUtil.insertImage(image, imgPath);
			return image;
		} catch (Exception e) {
		}
		return null;
	}

	private static void insertImage(BufferedImage source, String imgPath)
			throws Exception {
		File file = null;
		Image resource=null;
		if (imgPath.startsWith("http")) {
			URL fileUrl = new URL(imgPath);
			resource = ImageIO.read(fileUrl);
		} else {
			file = new File(imgPath);
			if (!file.exists()) {
				return;
			}
		   resource = ImageIO.read(file);
		}

		int QRcodeWidth = source.getWidth(null);
		int QRcodeHeighr = source.getHeight(null);		
		resource = compressImg(resource, QRcodeWidth / 6, QRcodeHeighr / 6);
		int width = resource.getWidth(null);
		int height = resource.getHeight(null);
		Graphics2D graph = source.createGraphics();
		int x = (QRcodeWidth - width) / 2;
		int y = (QRcodeHeighr - height) / 2;
		graph.drawImage(resource, x, y, width, height, null);
		Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
		graph.setStroke(new BasicStroke(3f));
		graph.draw(shape);
		graph.dispose();
	}

	/**
	 * compress image
	 * 
	 * @param resource
	 *            source image
	 * @param cwidth
	 * @param cheight
	 * @return compress result
	 */
	public static Image compressImg(Image resource, int cwidth, int cheight) {
		int width = resource.getWidth(null);
		int height = resource.getHeight(null);

		if (width > cwidth) {
			width = cwidth;
		}
		if (height > cheight) {
			height = cheight;
		}
		Image image = resource.getScaledInstance(width, height,
				Image.SCALE_SMOOTH);
		BufferedImage tag = new BufferedImage(width, height,
				BufferedImage.TYPE_INT_RGB);
		Graphics g = tag.getGraphics();
		g.drawImage(image, 0, 0, null); // draw shrink picture
		g.dispose();
		return image;
	}

	/**
	 * make dir
	 * 
	 * @param destPath
	 */
	public static void mkdirs(String destPath) {
		File file = new File(destPath);
		if (!file.exists() || !file.isDirectory()) {
			if (!file.isDirectory()) {
				long date = new Date().getTime();
				file.renameTo(new File(destPath + "_bat_" + date));
			}
			file.mkdirs();
		}
	}

	/**
	 * store QR image
	 * 
	 * @param content
	 * @param imgPath
	 *            logo path
	 * @param destPath
	 * @param QRCodesize
	 * @throws Exception
	 */
	public static void encode(String content, String imgPath, String destPath,
			int QRCodesize) {
		try {
			BufferedImage image = QRCodeUtil.createImage(content, imgPath,
					QRCodesize);
			mkdirs(destPath);
			String file = System.currentTimeMillis() + ".jpg";
			ImageIO.write(image, "jpg", new File(destPath + "/" + file));
		} catch (Exception e) {

		}
	}

	/**
	 * store QR image
	 * 
	 * @param content
	 * @param imgPath
	 *            LOGO
	 * @param destPath
	 *            store position
	 * @throws Exception
	 */
	public static void encode(String content, String imgPath, String destPath) {
		try {
			QRCodeUtil.encode(content, imgPath, destPath, 400);
		} catch (Exception e) {
		}
	}

	/**
	 * store QRCode
	 * 
	 * @param content
	 * @param destPath
	 *            store path
	 * @param QRCodesize
	 *            size
	 * @throws Exception
	 */
	public static void encode(String content, String destPath, int QRCodesize) {
		try {
			QRCodeUtil.encode(content, null, destPath, QRCodesize);
		} catch (Exception e) {
		}

	}

	/**
	 * output stream with logo
	 * 
	 * @param content
	 * @param imgPath
	 * @param output
	 * @param QRCodesize
	 * @throws Exception
	 */
	public static void encode(String content, String imgPath,
			OutputStream output, int QRCodesize) throws Exception {
		BufferedImage image = QRCodeUtil.createImage(content, imgPath,
				QRCodesize);
		ImageIO.write(image, "jpg", output);
		output.close();
	}

	/**
	 * output image stream
	 * 
	 * @param content
	 * @param output
	 * @param QRCodesize
	 * @throws Exception
	 */
	public static void encode(String content, OutputStream output,
			int QRCodesize) throws Exception {
		QRCodeUtil.encode(content, null, output, QRCodesize);
	}

	/**
	 * decode QR
	 * 
	 * @param file
	 *            input file
	 * @return return decode result
	 */
	public static String decode(File file) {
		if (!file.exists()) {
			return null;
		}
		try {
			BufferedImage image = ImageIO.read(file);
			return decode(image);
		} catch (Exception e) {
		}
		return null;
	}

	/**
	 * decode QR
	 * 
	 * @param url
	 *            QR address
	 * @return decode result
	 */
	public static String decode(URL url) {
		try {
			BufferedImage image = ImageIO.read(url);
			return decode(image);
		} catch (Exception e) {
		}
		return null;
	}

	/**
	 * decode QR
	 * 
	 * @param image
	 * @return decode result
	 */
	public static String decode(BufferedImage image) {
		if (image == null) {
			return null;
		}
		try {
			BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(
					image);
			BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
			Hashtable hashtable = new Hashtable();
			hashtable.put(DecodeHintType.CHARACTER_SET, CHARSET);
			Result result = new MultiFormatReader().decode(bitmap, hashtable);
			String resultStr = result.getText();
			return resultStr;
		} catch (Exception e) {
		}
		return null;
	}

	/**
	 * QR path address or disk path
	 * 
	 * @param path
	 * @return decode result
	 */
	public static String decode(String path) {
		if (path == null || path.isEmpty()) {
			return null;
		}
		try {
			if (path.startsWith("http")) {
				return QRCodeUtil.decode(new URL(path));
			} else {
				return QRCodeUtil.decode(new File(path));
			}
		} catch (Exception e) {
		}
		return null;
	}

//	public static void main(String[] args) throws Exception {
//		String text = "https://www.baidu.com";
//		String imagepath = "https://www.baidu.com/img/bd_logo1.png";
//		String localpath = "C:/test/AAA/skillcharts.PNG";
//		QRCodeUtil.encode(text, imagepath, "C:/test/AAA/", 400);
//
//		// QRCodeUtil.encode(text,"","C:/test/AAA/",true);
//
//		File file = new File("dddd");
//		if (!file.exists()) {
//			// System.out.println("file not exist");
//			// return;
//		}
//		String urlstring = "http://localhost:8080/DDD/getqrcode";
//		String dfdf = "C:/test/AAA/73196841.jpg";
//		// String result=QRCodeUtil.decode("C:/test/AAA/73196841.jpg");
//		String result = QRCodeUtil.decode(dfdf);
//		System.out.println(result);
//	}
}
